/*
 * ﻿Copyright (C) 2009-2013 NewMain Softech
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package com.newmainsoftech.gwetons.server;

import java.io.File;
import java.io.FileFilter;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * This class is just code holder, in order to take advantage of IDE's content assist and 
 * other features for coding beanshell script being used in ant file of this project.
 * The code here better be either ones demanded before Maven's test phase (so no need to say why not being 
 * able to move to source folder) or ones not suitable to put into any of test classes. Otherwise, such 
 * code should be moved to suitable test class and beanshell script in ant file should refer the yielded 
 * test class in the test output directory. <br />  
 * Coding note: Beanshell does not handle Generic and Annotation.
 * 
 * @author <a href="mailto:artymt@gmail.com">Arata Y.</a>
 */
public class ForBeanshell {
	// Ant class dummies --------------------------------------------------------------------------
	static interface AntProjectContractStub {
		Hashtable getProperties();
		String getProperty( String propertyName);
		void setProperty( String propertyName, String propertyValue);
		
		Hashtable getReferences();
		Object getReference( String key);
		
		void executeTarget( String targetName);
		void setNewProperty( String propertyName, String propertyValue);
	}
	static abstract class Project implements AntProjectContractStub {
	}
	Project project;
	
	static interface AntTargetContractStub {
		String getName();
	}
	static interface AntTaskContractStub {
		AntProjectContractStub getProject();
		void log( String message, int logLevel);
		void log( String message);
		String getTaskName();
		AntTargetContractStub getOwningTarget();
	}
	AntTaskContractStub self;
	
	static enum LogLevel {
        ERR( 0), WARN( 1), INFO( 2), VERBOSE( 3), DEBUG(4);
		private final int level;
			public int getLevel() {
				return level;
			}
		private LogLevel( int level) {
			this.level = level;
		}
	}
	// --------------------------------------------------------------------------------------------
	
	String getAntProperty( final String propertyName, final Object antProject) throws Exception {
		Method getPropertyMethod 
		= antProject.getClass().getMethod( "getProperty", new Class[]{ String.class});
		return (String)(getPropertyMethod.invoke( antProject, propertyName));
	}
	
	/**
	 * Define gwt.i18n.jvmarg property, gwt.i18n.outdir property, and gwt.i18n.interfaceName property 
	 * with default values if those are not defined.  
	 * Used at beanshell script of run_gwt_i18n_target_worker Ant target in antrun-gwt2.xml Ant build file. 
	 * 
	 * @throws Exception
	 */
	public void defineDefaultGwtI18nParameters() throws Exception {
		self.log( 
				String.format(
					"START %1$s TASK of %2$s TARGET >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
		
		final Hashtable propertyHashtable = project.getProperties();
			// Better not to use project.getProperty. When it returns null and assigned to variable, 
			// beanshell does not recognize it as null in regular Java way. Also, there seems 
			// to be problem of handing over object loaded by different class loader.
		
		// Define gwt.i18n.jvmarg property --------------------------------------------------------
		{
			final String gwtI18nJvmargPropertyName = "gwt.i18n.jvmarg";
			if ( !propertyHashtable.containsKey( gwtI18nJvmargPropertyName)) {
				project.setProperty( gwtI18nJvmargPropertyName, "-Xmx256M");
			}
		};
		// ----------------------------------------------------------------------------------------
		// Define gwt.i18n.outdir property --------------------------------------------------------
		{
			final String gwtI18nOutdirPropertyName = "gwt.i18n.outdir";
			File gwtI18nOutdir;
			if ( !propertyHashtable.containsKey( gwtI18nOutdirPropertyName)) {
				final String buildDirPropertyName = "project.build.directory";
				String buildDirPath = propertyHashtable.get( "project.build.directory").toString();
					if ( buildDirPath.lastIndexOf( File.separator) < (buildDirPath.length() - 1)) {
						buildDirPath = buildDirPath.concat( File.separator);
					}
				String gwtI18nOutdirStr 
				= buildDirPath.concat( "generated-sources").concat( File.separator).concat( "gwt");
				project.setProperty( gwtI18nOutdirPropertyName, gwtI18nOutdirStr);
				gwtI18nOutdir = new File( gwtI18nOutdirStr);
			}
			else {
				gwtI18nOutdir = new File( propertyHashtable.get( gwtI18nOutdirPropertyName).toString());
			}
			if ( !gwtI18nOutdir.exists()) gwtI18nOutdir.mkdirs();
		};
		// ----------------------------------------------------------------------------------------
		// Define gwt.i18n.type property ----------------------------------------------------------
		{
			final String createConstantsWithLookupOption = "-createConstantsWithLookup";
			final String createMessagesOption = "-createMessages";
			final String gwtI18nTypePropertyName = "gwt.i18n.type";
			String gwtI18nType;
			if ( !propertyHashtable.containsKey( gwtI18nTypePropertyName)) {
				project.setProperty( gwtI18nTypePropertyName, createMessagesOption);
			}
			else {
				gwtI18nType = propertyHashtable.get( gwtI18nTypePropertyName).toString();
					if ( !createConstantsWithLookupOption.equals( gwtI18nType) 
							&& !createMessagesOption.equals( gwtI18nType)) {
						throw new RuntimeException(
								String.format(
										"%1$s is improper as value for %1$s property. " 
										+ "Expect only either %2$s or %3$s.",
										new Object[]{
												gwtI18nType, 
												createConstantsWithLookupOption, 
												createMessagesOption 
												}
										)
								);
					}
			}
		};
		// ----------------------------------------------------------------------------------------
		// Define gwt.i18n.interfaceName property ------------------------------------------------
		{
			final String gwtI18nInterfaceNamePropertyName = "gwt.i18n.interfaceName";
			if ( !propertyHashtable.containsKey( gwtI18nInterfaceNamePropertyName)) {
				final String groupId = propertyHashtable.get( "project.groupId").toString();
				final String artifactId = propertyHashtable.get( "project.artifactId").toString(); 
				project.setProperty( 
						gwtI18nInterfaceNamePropertyName, 
						groupId.concat( ".").concat( artifactId).concat( ".client.Messages"));
			}
		};
		// ----------------------------------------------------------------------------------------
		
		self.log( 
				String.format(
					"END %1$s TASK of %2$s TARGET <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
	}
	
	/**
	 * Construct gwt.compile.war property for output .war file path if it's not defined.
	 * Used at beanshell script of set_gwt_compiler_war_property Ant target in 
	 * antrun-gwt2.xml Ant file.  
	 * 
	 * @throws Exception
	 */
	public void setGwtCompilerWarProperty() throws Exception {
		self.log( 
				String.format(
					"START %1$s TASK of %2$s TARGET >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
		
		final Hashtable propertyHashtable = project.getProperties();
			// Better not to use project.getProperty. When it returns null and assigned to variable, 
			// beanshell does not recognize it as null in regular Java way. Also, there seems 
			// to be problem of handing over object loaded by different class loader.
		
		// Construct gwt.compile.war property if it's not defined ----------------------------
		final String gwtCompilerWarPropertyName = "gwt.compile.war";
		if ( !propertyHashtable.containsKey( gwtCompilerWarPropertyName)) {
			final String buildDirPropertyName = "project.build.directory";
			if ( !propertyHashtable.containsKey( buildDirPropertyName)) {
				throw new RuntimeException(
						String.format(
								"%1$s property has not been defined. It's necessary to calculate " 
								+ "destination path of output .jar when %2$s property has not been defined.",
								new Object[]{
										buildDirPropertyName, 
										gwtCompilerWarPropertyName
										}
								)
						);
			}
			String buildDirPath = propertyHashtable.get( buildDirPropertyName).toString();
				if ( buildDirPath.lastIndexOf( File.separator) < (buildDirPath.length() - 1)) {
					buildDirPath = buildDirPath.concat( File.separator);
				}
				
			final String buildFinalNamePropertyName = "project.build.finalName";
			final String projectArtifactIdPropertyName = "project.artifactId";
			final String projectVersionPropertyName = "project.version";
			String buildFinalName;
				if ( propertyHashtable.containsKey( buildFinalNamePropertyName)) {
					buildFinalName = project.getProperty( buildFinalNamePropertyName);
				}
				else if ( propertyHashtable.containsKey( projectArtifactIdPropertyName) 
							&& propertyHashtable.containsKey( projectVersionPropertyName)) {
					buildFinalName 
					= project.getProperty( projectArtifactIdPropertyName)
						.concat( "-").concat( project.getProperty( projectVersionPropertyName));
				}
				else {
					throw new RuntimeException(
							String.format(
									"Missing necessary property defined; either %1$s property or the pair " 
									+ "of %2$s property and %3$s property is required to calculate " 
									+ "destination path of output .jar when %4$s has not been defined.",
									new Object[]{
											buildFinalNamePropertyName,
											projectArtifactIdPropertyName, 
											projectVersionPropertyName,
											gwtCompilerWarPropertyName
											}
									)
							);
				}
			String gwtCompilerWarPath = buildDirPath.concat( buildFinalName);
			
			project.setProperty( gwtCompilerWarPropertyName, gwtCompilerWarPath);
		}
		// ------------------------------------------------------------------------------------
		
		self.log( 
				String.format(
					"END %1$s TASK of %2$s TARGET <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
	}
	
	/**
	 * Define gwt.compile.jvmarg property and gwt.compile.args property with default values if those 
	 * are not defined.  
	 * Used at beanshell script in run-gwt-compiler-ant_target_worker Ant target. 
	 * 
	 * @throws Exception
	 */
	public void defineDefaultGwtCompilerParameters() throws Exception {
		self.log( 
				String.format(
					"START %1$s TASK of %2$s TARGET >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
		
		final Hashtable propertyHashtable = project.getProperties();
			// Better not to use project.getProperty. When it returns null and assigned to variable, 
			// beanshell does not recognize it as null in regular Java way. Also, there seems 
			// to be problem of handing over object loaded by different class loader.
		
		// Define default JVM arg given to GWT compiler if any is not defined -----------------
		final String gwtCompilerJvmargPropertyName = "gwt.compile.jvmarg";
		if ( !propertyHashtable.containsKey( gwtCompilerJvmargPropertyName)) {
			project.setProperty( gwtCompilerJvmargPropertyName, "-Xmx256M");
		}
		// ------------------------------------------------------------------------------------
		
		// Define default arg given to GWT compiler if any is not defined ---------------------
		final String gwtCompilerArgPropertyName = "gwt.compile.args";
		if ( !propertyHashtable.containsKey( gwtCompilerArgPropertyName)) {
			final String buildDirPropertyName = "project.build.directory";
			if ( !propertyHashtable.containsKey( buildDirPropertyName)) {
				throw new RuntimeException(
						String.format(
								"%1$s property has not been defined. It's necessary to " 
								+ "calculate the default directory into which deployable output " 
								+ "files will be written when %1$s property value is not provided.",
								new Object[]{
										buildDirPropertyName, 
										gwtCompilerArgPropertyName
										}
								)
						);
			}
			final String buildDirPath = propertyHashtable.get( buildDirPropertyName).toString();
			final String gwtcGenDir = "-gen " + buildDirPath + File.separator + "gwtc-generated";
			final String extraDir = "-extra " + buildDirPath + File.separator + "gwtc-extra";
			
			project.setProperty( 
					gwtCompilerArgPropertyName, 
					"-logLevel INFO -style OBF -localWorkers 1 -compileReport " 
					+ gwtcGenDir + " " + extraDir);
		}
		// ------------------------------------------------------------------------------------
		
		self.log( 
				String.format(
					"END %1$s TASK of %2$s TARGET <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
	}
	
	/**
	 * Build up source paths into antrun-gwt-compile.path reference. <br />
	 * Had been used at beanshell script in build-gwt-source-paths-ant_task Ant target of  
	 * antrun-gwt2.xml Ant file. Dropped by replacing with mvnpath tag for simplicity.<br />
	 * Input:
	 * <ul>
	 * <li>antrun-gwt.project.sources: optional<br />
	 * To specify source directories (what are separated each other by semi-collon character) for 
	 * compilation, instead of using default values.<br /> 
	 * Defaults to: ${project.build.sourceDirectory};
	 * ${project.build.directory}${file.separator}generated-sources${file.separator}gwt;
	 * ${basedir}${file.separator}src${file.separator}main${file.separator}resources
	 * </li>
	 * <li>antrun-gwt-compile.path reference</li>
	 * </ul>
	 * @deprecated
	 * @throws Exception
	 */
	public void constructAntrunGwtCompilePath() throws Exception {
		self.log( 
				String.format(
					"START %1$s TASK of %2$s TARGET >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
		
		Object gwtCompilePathObj = self.getProject().getReference( "antrun-gwt-compile.path");
			if ( gwtCompilePathObj == null) {
				throw new RuntimeException(
						"Could not get reference to tne ant path element, with "
						+ "antrun-gwt-compile.path id, what should have already been defined." );
			}
			Method createPathElementMethod 
			= gwtCompilePathObj.getClass().getMethod( "createPathElement", (Class[])null);
				createPathElementMethod.setAccessible( true);
		final Hashtable propertyHashtable = project.getProperties();
			// Better not to use project.getProperty. When it returns null and assigned to variable, 
			// beanshell does not recognize it as null in regular Java way. Also, there seems 
			// to be problem of handing over object loaded by different class loader.
		if ( !propertyHashtable.containsKey( "antrun-gwt.project.sources")) {
			// add project.build.sourceDirectory property to antrun-gwt-compile.path Path object. 
			String projectBuildSourceDirStr 
			= (String)(propertyHashtable.get( "project.build.sourceDirectory"));
				File projectBuildSourceDirObj = new File( projectBuildSourceDirStr);
				if ( !projectBuildSourceDirObj.exists() || !projectBuildSourceDirObj.isDirectory()) {
					throw new RuntimeException(
							"Could not resolve " + projectBuildSourceDirStr + " as existing "
							+ "directory where is expected holding source .java files for compilation." );
				}
				{
					Object pathElevemnt = createPathElementMethod.invoke( gwtCompilePathObj, (Object[])null);
					Method setPathMethod 
					= pathElevemnt.getClass().getMethod( "setPath", new Class[]{ String.class});
						setPathMethod.setAccessible( true);
					setPathMethod.invoke( pathElevemnt, projectBuildSourceDirStr);
				}
			// add ${project.build.directory}/generated-sources/gwt to antrun-gwt-compile.path Path object.
			String buildDirStr 
			= (String)(propertyHashtable.get( "project.build.directory"));
				if ( buildDirStr.lastIndexOf( File.separator) < (buildDirStr.length() - 1)) {
					buildDirStr = buildDirStr.concat( File.separator);
				}
			String generatedSourcesGwtDirStr 
			= buildDirStr.concat( "generated-sources").concat( File.separator).concat( "gwt");
				File generatedSourcesGwtDirObj = new File( generatedSourcesGwtDirStr);
		    	if ( generatedSourcesGwtDirObj.exists() && generatedSourcesGwtDirObj.isDirectory()) {
					Object pathElevemnt = createPathElementMethod.invoke( gwtCompilePathObj, (Object[])null);
					Method setPathMethod 
					= pathElevemnt.getClass().getMethod( "setPath", new Class[]{ String.class});
						setPathMethod.setAccessible( true);
		    		setPathMethod.invoke( pathElevemnt, generatedSourcesGwtDirStr);
		    	}
		    	else {
		    		self.log(
						"Could not resolve " + generatedSourcesGwtDirStr + " as existing "
						+ "directory where is expected holding auto-generated .java files. "
						+ "Thereby, skipping to add it to class-path for compilation.", 
		    			LogLevel.DEBUG.getLevel()
		    			);
		    	}
			
			// add project resources directory to antrun-gwt-compile.path Path object. 
			// Assume that resource directory is src/main/resources
			String baseDirStr = (String)(propertyHashtable.get( "basedir"));
				if ( baseDirStr.lastIndexOf( File.separator) < ( baseDirStr.length() - 1)) {
					baseDirStr = baseDirStr.concat( File.separator);
				}
			String resourcesDirStr = baseDirStr
				.concat( "src").concat( File.separator)
				.concat( "main").concat( File.separator)
				.concat( "resources");
		
			File resourcesDirObj = new File( resourcesDirStr);
	    	if (( !resourcesDirObj.exists()) || ( !resourcesDirObj.isDirectory())) {
	    		self.log(
					"Could not resolve " + resourcesDirStr + " as existing "
					+ "directory where is expected holding .gwt.xml file. "
					+ "Thereby, skipping to add it to class-path.", 
					LogLevel.DEBUG.getLevel()
					);
	    	}
	    	else {
				Object pathElevemnt = createPathElementMethod.invoke( gwtCompilePathObj, (Object[])null);
				Method setPathMethod 
				= pathElevemnt.getClass().getMethod( "setPath", new Class[]{ String.class});
					setPathMethod.setAccessible( true);
				setPathMethod.invoke( pathElevemnt, resourcesDirStr);
	    	}
		}
		else {
			String gwtProjectSourcesStr 
			= (String)(propertyHashtable.get( "antrun-gwt.project.sources"));
			String[] sourceArray = gwtProjectSourcesStr.split( ";");
			for( int indexOnSourceArray = 0; indexOnSourceArray < sourceArray.length; indexOnSourceArray++) {
				String sourceStr 
				= sourceArray[ indexOnSourceArray].replaceFirst("^\\s+", "").replaceFirst( "\\s+$", "");
		
				File sourceFile = new File( sourceStr);
				if ( sourceFile.exists()) {
					Object pathElevemnt = createPathElementMethod.invoke( gwtCompilePathObj, (Object[])null);
					Method setPathMethod 
					= pathElevemnt.getClass().getMethod( "setPath", new Class[]{ String.class});
						setPathMethod.setAccessible( true);
					setPathMethod.invoke( pathElevemnt, sourceStr);
				}
				else {
					self.log(
						"Skipped to add " + sourceStr + " to class-path for compilation " 
						+ "since it doesn't exist.",
						LogLevel.INFO.getLevel()
						);
				}
			} // for
		}
		
		self.log( 
				String.format(
					"END %1$s TASK of %2$s TARGET <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
	}
	
	/**
	 * Define gwt.devmode.module property, gwt.devmode.jvmarg property, and 
	 * gwt.devmode.startupUrl property with default values if those are not defined.  
	 * Used at beanshell script in run_gwt_dev_mode_target_worker Ant target of  
	 * antrun-gwt2.xml Ant file. 
	 *  
	 * @throws Exception
	 */
	public void defineDefaultGwtDevmodeParameters() throws Exception {
		self.log( 
				String.format(
					"START %1$s TASK of %2$s TARGET >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
		
		final Hashtable propertyHashtable = project.getProperties();
			// Better not to use project.getProperty. When it returns null and assigned to variable, 
			// beanshell does not recognize it as null in regular Java way. Also, there seems 
			// to be problem of handing over object loaded by different class loader.
	
		// Provide default value to gwt.devmode.module property if it's not defined -------
		{
			final String gwtDevmodeModulePropertyName = "gwt.devmode.module";
			if ( !propertyHashtable.containsKey( gwtDevmodeModulePropertyName)) {
				final String gwtCompileModulesPropertyName = "gwt.compile.modules";
				if ( !propertyHashtable.containsKey( gwtCompileModulesPropertyName)) {
					throw new RuntimeException(
							String.format(
									"Could not yeild default value for %1$s property out of value of " 
									+ "%2$s property since %2$s property has not been defined too.",
									new Object[]{ 
											gwtDevmodeModulePropertyName, 
											gwtCompileModulesPropertyName}
									)
							);
				}
				String gwtCompileModules = propertyHashtable.get( gwtCompileModulesPropertyName).toString();
				String[] compileModuleArray = gwtCompileModules.trim().split( " ");
					if ( compileModuleArray.length < 1) {
						throw new RuntimeException(
								String.format(
										"Could not yeild default value for %1$s property out of value of " 
										+ "%2$s property: %3$s.",
										new Object[]{ 
											gwtDevmodeModulePropertyName, 
											gwtCompileModulesPropertyName,
											Arrays.toString( compileModuleArray)}
										)
								);
					}
					self.getProject()
					.setNewProperty( gwtDevmodeModulePropertyName, compileModuleArray[ 0].trim());
			}
		};
		// --------------------------------------------------------------------------------
		
		// Provide default value to gwt.devmode.jvmarg property if it's not defined -------
		{
			final String gwtDevmodeJvmargPropertyName = "gwt.devmode.jvmarg";
			if ( !propertyHashtable.containsKey( gwtDevmodeJvmargPropertyName)) {
				self.getProject()
				.setNewProperty( gwtDevmodeJvmargPropertyName, "-Xmx256M");
			}
		};
		// --------------------------------------------------------------------------------
		
		// Provide default value to gwt.devmode.startupUrl property if it's not defined ---
		{
			final String gwtDevmodeStartupUrlPropertyName = "gwt.devmode.startupUrl";
			if ( !propertyHashtable.containsKey( gwtDevmodeStartupUrlPropertyName)) {
				final String artifactIdPropertyName = "project.artifactId"; 
				final String artifactId = propertyHashtable.get( artifactIdPropertyName).toString();
				
				final String gwtCompilerWarPropertyName = "gwt.compile.war";
				final String gwtCompilerWarProperty 
				= propertyHashtable.get( gwtCompilerWarPropertyName).toString();
				File gwtCompilerWarDir = new File( gwtCompilerWarProperty);
					if ( !gwtCompilerWarDir.exists() || !gwtCompilerWarDir.isDirectory()) {
						throw new RuntimeException(
								String.format(
										"%1$s property value (%2$s) does not point to directory.",
										new Object[]{
												gwtCompilerWarPropertyName, 
												gwtCompilerWarProperty}
										)
								);
					}
				FileFilter fileFilter = new FileFilter() {
					public boolean accept( File pathname) {
						if ( pathname.isDirectory()) return false;
						
						if ( !pathname.getName().matches( ".+\\.html?$")) return false;
						
						final String fileName 
						= pathname.getName().toLowerCase()
							.substring( 0, pathname.getName().lastIndexOf( "."));
						if ( !fileName.equals( artifactId.toLowerCase())) return false;
						return true;
					}
				}; 
				
				File[] fileArray = gwtCompilerWarDir.listFiles( fileFilter);
					if ( fileArray.length != 1) {
						throw new RuntimeException(
								String.format(
										"Could not find .htm or .html file in %1$s as default value of " 
										+ "start-up URL for GWT dev-mode. Please provide it as %2$s property.",
										new Object[]{
												gwtCompilerWarProperty,
												gwtDevmodeStartupUrlPropertyName}
										)
								);
					}
				String gwtDevmodeStartupUrl = fileArray[ 0].getPath().replace( "\\", "/");
				project.setProperty( gwtDevmodeStartupUrlPropertyName, gwtDevmodeStartupUrl);
			}
		}
		// --------------------------------------------------------------------------------
		
		// Provide default value to gwt.devmode.args property if it's not defined ---------
		//something like -Djava.util.logging.config.file=test/com/inetools/gwetons/client/devModeTest.logging.properties
/*		final String gwtDevmodeArgsPropertyName = "gwt.devmode.args";
		if ( !propertyHashtable.containsKey( gwtDevmodeArgsPropertyName)) {
		}
*/
		// --------------------------------------------------------------------------------
		
		self.log( 
				String.format(
					"END %1$s TASK of %2$s TARGET <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
	}
	
	
	/**
	 * Build up test source paths into antrun-gwt-test.path reference. <br />
	 * Had been used at beanshell script in run-gwt-test-ant_target_worker Ant target of  
	 * antrun-gwt2.xml Ant file. Dropped by replacing with mvnpath tag for simplicity.<br />
	 * Input:
	 * <ul>
	 * <li>gwt.test.sources: optional<br />
	 * To specify test source directories (what are separated each other by semi-collon character) for 
	 * compilation, instead of using default values.<br /> 
	 * Defaults to: ${project.build.testSourceDirectory};
	 * ${project.build.testSourceDirectory}${file.separator}..${file.separator}resources;
	 * ${project.build.testOutputDirectory};
	 * ${basedir}${file.separator}src${file.separator}test${file.separator}resources
	 * </li>
	 * <li>antrun-gwt-test.path reference</li>
	 * </ul>
	 * 
	 * @deprecated
	 * @throws Exception
	 */
	public void constructAntrunGwtTestPath() throws Exception {
		self.log( 
				String.format(
					"START %1$s TASK of %2$s TARGET >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
		
		// Build up antrun-gwt-test.path Path object -----------------------------------------
		Object gwtTestPathObj = self.getProject().getReference( "antrun-gwt-test.path");
			if ( gwtTestPathObj == null) {
				throw new RuntimeException(
						"Could not get reference to tne ant path element, with "
						+ "antrun-gwt-test.path id, what should have already been defined.");
			}
			Method createPathElementMethod 
			= gwtTestPathObj.getClass().getMethod( "createPathElement", (Class[])null);
				createPathElementMethod.setAccessible( true);
		
		final Hashtable propertyHashtable = project.getProperties();
			// Better not to use project.getProperty. When it returns null and assigned to variable, 
			// beanshell does not recognize it as null in regular Java way. Also, there seems 
			// to be problem of handing over object loaded by different class loader.
		
		if ( !propertyHashtable.containsKey( "gwt.test.sources")) {
			String gwtTestSourceDirStr  
			= (String)(propertyHashtable.get( "project.build.testSourceDirectory"));
				File gwtTestSourceDirObj = new File( gwtTestSourceDirStr);
				if ( !gwtTestSourceDirObj.exists() || !gwtTestSourceDirObj.isDirectory()) {
					throw new RuntimeException(
							"Could not resolve " + gwtTestSourceDirStr + " as existing directory "
							+ "where is expected holding test source .java files.");
				}
				Method setPathMethod;
				{
					Object pathElementObj = createPathElementMethod.invoke( gwtTestPathObj, (Object[])null);
					setPathMethod 
					= pathElementObj.getClass().getMethod( "setPath", new Class[]{ String.class});
						setPathMethod.setAccessible( true);
					setPathMethod.invoke( pathElementObj, gwtTestSourceDirStr);
				}
			String gwtTestResourceDirStr 
			= gwtTestSourceDirStr.replaceFirst( File.separator.concat( "\\s*$"), ""); 
				gwtTestResourceDirStr 
				= gwtTestResourceDirStr
					.substring( 0, gwtTestResourceDirStr.lastIndexOf( File.separator) + 1)
					.concat( "resources");
				File gwtTestResourceDirObj = new File( gwtTestResourceDirStr);
				if ( gwtTestResourceDirObj.exists() && gwtTestResourceDirObj.isDirectory()) {
					Object pathElementObj = createPathElementMethod.invoke( gwtTestPathObj, (Object[])null);
					setPathMethod.invoke( pathElementObj, gwtTestResourceDirStr);
				}
				else {
		    		self.log(
						"Could not resolve " + gwtTestResourceDirStr + " as existing "
						+ "directory where may be expected holding test resource files (including "
						+ ".gwt.xml file specific for test.) Thereby, skipping to add it to "
						+ "class-path for compilation.", 
		    			LogLevel.INFO.getLevel()
		    			);
				}
		
			String gwtTestOutputDirStr
			= (String)(propertyHashtable.get( "project.build.testOutputDirectory"));
				File gwtTestOutputDirObj = new File( gwtTestOutputDirStr);
				if ( gwtTestOutputDirObj.exists() && gwtTestOutputDirObj.isDirectory()) {
					Object pathElementObj = createPathElementMethod.invoke( gwtTestPathObj, (Object[])null);
					setPathMethod.invoke( pathElementObj, gwtTestResourceDirStr);
				}
				else {
					throw new RuntimeException(
							"Could not resolve " + gwtTestOutputDirStr + " as existing directory "
							+ "where is expected holding compiled test .class files.");
				}
			
		}
		else {
			String gwtTestSourcesStr = (String)(propertyHashtable.get( "gwt.test.sources"));
			String[] testSourceArray = gwtTestSourcesStr.split( ";");
			for( 	int indexOnTestSourceArray = 0; 
					indexOnTestSourceArray < testSourceArray.length;
					indexOnTestSourceArray++) 
			{
				String testSourceStr 
				= testSourceArray[ indexOnTestSourceArray]
						.replaceFirst( "^\\s+", "").replace( "\\s+$", "");
					File testSourceFile = new File( testSourceStr);
					if ( testSourceFile.exists()) {
						Object pathElementObj 
						= createPathElementMethod.invoke( gwtTestPathObj, (Object[])null);
						Method setPathMethod 
						= pathElementObj.getClass().getMethod( "setPath", new Class[]{ String.class});
							setPathMethod.setAccessible( true);
						setPathMethod.invoke( pathElementObj, testSourceStr);
					}
					else {
						self.log(
							"Skipped to add " + testSourceStr + " to class-path for test " 
							+ "since it doesn't exist.",
							LogLevel.INFO.getLevel()
							);
					}
			} // for
		}
		
		// append antrun-gwt-compile.path to antrun-gwt-test.path 
		Object gwtCompilePathObj = self.getProject().getReference( "antrun-gwt-compile.path");
			if ( gwtCompilePathObj == null) {
				throw new RuntimeException(
						"Could not get reference to tne ant path element, with "
						+ "antrun-gwt-compile.path id, what should have already been defined.");
			}
		
		Method sizeMethod = gwtCompilePathObj.getClass().getMethod( "size", (Class[])null);
			sizeMethod.setAccessible( true);
		int gwtCompilePathSize = (Integer)(sizeMethod.invoke( gwtCompilePathObj, (Object[])null));
		if ( gwtCompilePathSize < 1) {
			self.getProject().executeTarget( "build-gwt-paths-ant_task");
		}
		Method appendMethod 
		= gwtTestPathObj.getClass().getMethod( "append", new Class[]{ gwtCompilePathObj.getClass()});
			appendMethod.setAccessible( true);
		appendMethod.invoke( gwtTestPathObj, gwtCompilePathObj);
		// --------------------------------------------------------------------------------
		
		self.log( 
				String.format(
					"END %1$s TASK of %2$s TARGET <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
	}
	
	/**
	 * Define gwt.devtest.report property, gwt.devtest.jvmarg property, gwt.devtest.gwtargs 
	 * property, gwt.devtest.incldue property, and gwt.devtest.testmethods property with default 
	 * values if those are not defined.  
	 * Had used at beanshell script of run_gwt_dev_test_target_worker Ant target of 
	 * antrun-gwt2.xml Ant file, but it's replaced by run_gwt_test_target_worker.
	 * 
	 * @deprecated
	 * @throws Exception
	 */
	public void defineDefaultGwtDevTestParameters() throws Exception {
		self.log( 
				String.format(
					"START %1$s TASK of %2$s TARGET >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
		
		final Hashtable propertyHashtable = project.getProperties();
			// Better not to use project.getProperty. When it returns null and assigned to variable, 
			// beanshell does not recognize it as null in regular Java way. Also, there seems 
			// to be problem of handing over object loaded by different class loader.
	
		String buildDirStr 
		= (String)(propertyHashtable.get( "project.build.directory"));
			if ( buildDirStr.lastIndexOf( File.separator) < (buildDirStr.length() - 1)) {
				buildDirStr = buildDirStr.concat( File.separator);
			}
			
		// Provide default value to gwt.devtest.report property if it's not defined -------
		{
			final String gwtDevTestReportPropertyName = "gwt.devtest.report";
			if ( !propertyHashtable.containsKey( gwtDevTestReportPropertyName)) {
				final String gwtDevTestReportDirStr 
				= buildDirStr.concat( "gwt-test-reports").concat( File.separator).concat( "htmlunit.dev");
				final File gwtDevTestReportDir = new File( gwtDevTestReportDirStr);
					if ( !gwtDevTestReportDir.exists()) gwtDevTestReportDir.mkdirs();
				self.getProject()
				.setNewProperty( gwtDevTestReportPropertyName, gwtDevTestReportDir.getAbsolutePath());
			}
		};
		// --------------------------------------------------------------------------------
		
		// Provide default value to gwt.devtest.jvmarg property if it's not defined -------
		{
			final String gwtDevtestJvmargPropertyName = "gwt.devtest.jvmarg";
			if ( !propertyHashtable.containsKey( gwtDevtestJvmargPropertyName)) {
				project.setProperty( gwtDevtestJvmargPropertyName, "-Xmx256M");
			}
		};
		// --------------------------------------------------------------------------------
		
		// Provide default value to gwt.devtest.gwtargs property if it's not defined ------
		{
			final String gwtDevtestGwtargsPropertyName = "gwt.devtest.gwtargs";
			if ( !propertyHashtable.containsKey( gwtDevtestGwtargsPropertyName)) {
				String gwtDevtestWarDirStr = buildDirStr.concat( "gwt-www-test");
				self.getProject()
				.setNewProperty( 
						gwtDevtestGwtargsPropertyName, 
						"-standardsMode -war ".concat( gwtDevtestWarDirStr).concat( " -logLevel INFO"));
			}
			else {
				String gwtDevtestGwtargsProperty 
				= propertyHashtable.get( gwtDevtestGwtargsPropertyName).toString();
				if ( !gwtDevtestGwtargsProperty.matches( "([^\\s]*\\s+)*-prod(\\s+[^\\s]*.*)*")) {
					throw new RuntimeException(
							String.format(
									"Given value to %1$s property does not contain -prod pararmeter: %2$s",
									new Object[]{ gwtDevtestGwtargsPropertyName, gwtDevtestGwtargsProperty}
									)
							);
				}
			}
		};
		// --------------------------------------------------------------------------------
		
		// Provide default value to gwt.devtest.incldue property if it's not defined ------
		{
			final String gwtDevtestInclduePropertyName = "gwt.devtest.incldue";
			if ( !propertyHashtable.containsKey( gwtDevtestInclduePropertyName)) {
				self.getProject()
				.setNewProperty(  gwtDevtestInclduePropertyName, "**/GwtTest*.java");
			}
		};
		// --------------------------------------------------------------------------------

		// Provide default value to gwt.devtest.testmethods property if it's not defined --
		{
			final String gwtDevtestTestmethodsPropertyName = "gwt.devtest.testmethods";
			if ( !propertyHashtable.containsKey( gwtDevtestTestmethodsPropertyName)) {
				self.getProject()
				.setNewProperty(  gwtDevtestTestmethodsPropertyName, "*");
			}
		};
		// --------------------------------------------------------------------------------
		
		self.log( 
				String.format(
					"END %1$s TASK of %2$s TARGET <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
	}
	
	/**
	 * Check whether version of Ant used is 1.8 or higher since Ant's local task is used in 
	 * run_gwt_test_target_worker Ant target.  
	 * Used at beanshell script of varidate_ant_version_target Ant target of antrun-gwt2.xml Ant file. 
	 * 
	 * @throws Exception
	 */
	public void varidateAntVersion() {
		self.log( 
				String.format(
					"START %1$s TASK of %2$s TARGET >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
		
		final Hashtable propertyHashtable = project.getProperties();
			// Better not to use project.getProperty. When it returns null and assigned to variable, 
			// beanshell does not recognize it as null in regular Java way. Also, there seems 
			// to be problem of handing over object loaded by different class loader.
		
		final String antVersionPropertyName = "ant.version";
		String antVersion = propertyHashtable.get( antVersionPropertyName).toString();
			final String delimiter = "version ";
			final String versionRegExp = ".* version ([0-9\\.]+) .*";
			final Pattern pattern = Pattern.compile( versionRegExp);
			final Matcher matcher = pattern.matcher( antVersion);
			if ( matcher.find()) {
				antVersion = matcher.group( 1);
				int delimiterIndex = antVersion.indexOf( ".");
				int antMajorVersion 
				= Integer.parseInt( antVersion.substring( 0, delimiterIndex));
					if ( antMajorVersion < 1) {
						throw new RuntimeException(
								String.format(
										"Requires version of Ant equals 1.8 or higher since " 
										+ "going to use Ant's local task, but available version of " 
										+ "Ant is %1$s.",
										antVersion
										)
								);
					}
					else if ( antMajorVersion < 2) {
						int antMinorVersion 
						= Integer.parseInt( 
								antVersion.substring( 
										delimiterIndex + 1, 
										antVersion.indexOf( ".", delimiterIndex + 1)));
						if ( antMinorVersion < 8) {
							throw new RuntimeException(
									String.format(
											"Requires version of Ant equals 1.8 or higher since " 
											+ "going to use Ant's local task, but available version of " 
											+ "Ant is %1$s.",
											antVersion
											)
									);
						}
					}
			}
			else {
				throw new RuntimeException(
						String.format(
								"Could not extract version info out of value of %1$s property: %2$s",
								new Object[]{
										antVersionPropertyName,
										antVersion
										}
								)
						);
			}
		
		self.log( 
				String.format(
					"END %1$s TASK of %2$s TARGET <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
	}
	
	/**
	 * Define gwt.test.testclass property, gwt.test.testmethods property, gwt.test.incldue property, 
	 * gwt.test.exclude property, gwt.test.report property, gwt.test.jvmarg property, and 
	 * gwt.test.gwtargs property with default values.  
	 * Used at beanshell script of run_gwt_test_target_worker Ant target of antrun-gwt2.xml Ant file. 
	 * 
	 * @throws Exception
	 */
	public void defineDefaultGwtTestParameters() throws Exception {
		self.log( 
				String.format(
					"START %1$s TASK of %2$s TARGET >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
		
		final Hashtable propertyHashtable = project.getProperties();
			// Better not to use project.getProperty. When it returns null and assigned to variable, 
			// beanshell does not recognize it as null in regular Java way. Also, there seems 
			// to be problem of handing over object loaded by different class loader.
	
		final String propertyGwtPrefix = "gwt.";
		
		// gwt.test.mode
		final String gwtDevTestMode = "dev";
		final String gwtProdTestMode = "prod";
		String gwtTestMode;
		{
			final String gwtTestModePropertyName = propertyGwtPrefix.concat( "test.mode");
			if ( !propertyHashtable.containsKey( gwtTestModePropertyName)) {
				throw new RuntimeException(
						String.format(
								"%1$s property has not been defined to switch between development mode " 
								+ "and production mode of GWT test.",
								new Object[]{ gwtTestModePropertyName}
								)
						);
			}
			gwtTestMode = propertyHashtable.get( gwtTestModePropertyName).toString().toLowerCase().trim();
				if ( !gwtDevTestMode.equals( gwtTestMode) && !gwtProdTestMode.equals( gwtTestMode)) {
					throw new RuntimeException(
							String.format(
									"Inproper value of %1$s property: expected either %2$s or %3$s but " 
									+ "actual value is %4$s.",
									new Object[]{ 
											gwtTestModePropertyName, 
											gwtDevTestMode, 
											gwtProdTestMode, 
											gwtTestMode
											}
									)
							);
				}
		}
		
		String buildDirStr 
		= (String)(propertyHashtable.get( "project.build.directory"));
			if ( buildDirStr.lastIndexOf( File.separator) < (buildDirStr.length() - 1)) {
				buildDirStr = buildDirStr.concat( File.separator);
			}
			
		// Define gwt.test.testclass property -----------------------------------------------------
		String gwtTestTestclassProperty = "";
		{
			final String gwtTestTestclassPropertySuffix = "test.testclass";
			final String gwtTestTestclassPropertyName 
			= propertyGwtPrefix.concat( gwtTestMode).concat( gwtTestTestclassPropertySuffix);
			if ( propertyHashtable.containsKey( gwtTestTestclassPropertyName)) {
				gwtTestTestclassProperty 
				= propertyHashtable.get( gwtTestTestclassPropertyName).toString();
				self.getProject()
				.setProperty( 
						propertyGwtPrefix.concat( gwtTestTestclassPropertySuffix), 
						gwtTestTestclassProperty);
			}
		}
		// ----------------------------------------------------------------------------------------
		// Define gwt.test.testmethods property ---------------------------------------------------
		if ( !"".equals( gwtTestTestclassProperty)) {
			final String gwtTestTestmethodsPropertySuffix = "test.testmethods";
			final String gwtTestTestmethodsPropertyName 
			= propertyGwtPrefix.concat( gwtTestMode).concat( gwtTestTestmethodsPropertySuffix);
			if ( propertyHashtable.containsKey( gwtTestTestmethodsPropertyName)) {
				self.getProject()
				.setProperty( 
						propertyGwtPrefix.concat( gwtTestTestmethodsPropertySuffix), 
						propertyHashtable.get( gwtTestTestmethodsPropertyName).toString());
			}
		}
		// ----------------------------------------------------------------------------------------
		// Define gwt.test.incldue property -------------------------------------------------------
		if ( "".equals( gwtTestTestclassProperty)) {
			final String gwtTestInclduePropertySuffix = "test.incldue";
			final String gwtTestInclduePropertyName 
			= propertyGwtPrefix.concat( gwtTestMode).concat( gwtTestInclduePropertySuffix);
			if ( propertyHashtable.containsKey( gwtTestInclduePropertyName)) {
				self.getProject()
				.setProperty( 
						propertyGwtPrefix.concat( gwtTestInclduePropertySuffix), 
						propertyHashtable.get( gwtTestInclduePropertyName).toString());
			}
			else { // Set default value
				self.getProject()
				.setProperty( 
						propertyGwtPrefix.concat( gwtTestInclduePropertySuffix), 
						"**/GwtTest*.java");
			}
		}
		// ----------------------------------------------------------------------------------------
		// Define gwt.test.exclude property -------------------------------------------------------
		if ( "".equals( gwtTestTestclassProperty)) {
			final String gwtTestExcludePropertySuffix = "test.exclude";
			final String gwtTestExcludePropertyName 
			= propertyGwtPrefix.concat( gwtTestMode).concat( gwtTestExcludePropertySuffix);
			if ( propertyHashtable.containsKey( gwtTestExcludePropertyName)) {
				self.getProject()
				.setProperty( 
						propertyGwtPrefix.concat( gwtTestExcludePropertySuffix), 
						propertyHashtable.get( gwtTestExcludePropertyName).toString());
			}
		}
		// ----------------------------------------------------------------------------------------
		// Define gwt.test.report property --------------------------------------------------------
		{
			final String gwtTestReportPropertySuffix = "test.report";
			final String gwtTestReportPropertyName 
			= propertyGwtPrefix.concat( gwtTestMode).concat( gwtTestReportPropertySuffix);
			if ( propertyHashtable.containsKey( gwtTestReportPropertyName)) {
				self.getProject()
				.setProperty( 
						propertyGwtPrefix.concat( gwtTestReportPropertySuffix), 
						propertyHashtable.get( gwtTestReportPropertyName).toString());
			}
			else { // Set default value
				final String gwtTestReportDirStr 
				= buildDirStr.concat( "gwt-test-reports").concat( File.separator)
					.concat( "htmlunit.").concat( gwtTestMode);
				final File gwtTestReportDir = new File( gwtTestReportDirStr);
					if ( !gwtTestReportDir.exists()) gwtTestReportDir.mkdirs();
				
				self.getProject()
				.setProperty( 
						propertyGwtPrefix.concat( gwtTestReportPropertySuffix), 
						gwtTestReportDirStr);
			}
		};
		// ----------------------------------------------------------------------------------------
		// Define gwt.test.jvmarg property --------------------------------------------------------
		{
			final String gwtTestJvmargPropertySuffix = "test.jvmarg";
			final String gwtTestJvmargPropertyName 
			= propertyGwtPrefix.concat( gwtTestMode).concat( gwtTestJvmargPropertySuffix);
			if ( propertyHashtable.containsKey( gwtTestJvmargPropertyName)) {
				self.getProject()
				.setProperty( 
						propertyGwtPrefix.concat( gwtTestJvmargPropertySuffix), 
						propertyHashtable.get( gwtTestJvmargPropertyName).toString().trim());
			}
			else { // Set default value
				self.getProject()
				.setProperty( 
						propertyGwtPrefix.concat( gwtTestJvmargPropertySuffix), 
						"-Xmx256M");
			}
		};
		// ----------------------------------------------------------------------------------------
		// Define gwt.test.gwtargs property -------------------------------------------------------
		{
			final String gwtTestGwtargsPropertySuffix = "test.gwtargs";
			final String gwtTestGwtargsPropertyName 
			= propertyGwtPrefix.concat( gwtTestMode).concat( gwtTestGwtargsPropertySuffix);
			if ( propertyHashtable.containsKey( gwtTestGwtargsPropertyName)) {
				final String gwtTestGwtargsPropertyValue 
				= propertyHashtable.get( gwtTestGwtargsPropertyName).toString()
					.replaceAll( "[\\t\\n\\r\\f]+", " ").trim();
					final String prodParameterRegExp = "([^\\s]*\\s+)*-prod(\\s+[^\\s]*.*)*";
					if ( gwtDevTestMode.equals( gwtTestMode)) {
						if ( gwtTestGwtargsPropertyValue.matches( prodParameterRegExp)) {
							throw new RuntimeException(
									String.format(
											"Given value to %1$s property contains -prod pararmeter: %2$s",
											new Object[]{ 
													gwtTestGwtargsPropertyName, 
													gwtTestGwtargsPropertyValue}
											)
									);
						}
					}
					else if ( gwtProdTestMode.equals( gwtTestMode)) {
						if ( !gwtTestGwtargsPropertyValue.matches( prodParameterRegExp)) {
							throw new RuntimeException(
									String.format(
											"Given value to %1$s property does not contain -prod " 
											+ "pararmeter: %2$s",
											new Object[]{ 
													gwtTestGwtargsPropertyName, 
													gwtTestGwtargsPropertyValue}
											)
									);
						}
					}
				self.getProject()
				.setProperty( 
						propertyGwtPrefix.concat( gwtTestGwtargsPropertySuffix), 
						gwtTestGwtargsPropertyValue);
			}
			else { // Set default value
				String gwtTestWarDirStr = buildDirStr.concat( "gwt-test");
				if ( gwtDevTestMode.equals( gwtTestMode)) {
					gwtTestWarDirStr = gwtTestWarDirStr.concat( File.separator).concat( "dev-mode");
					self.getProject()
					.setNewProperty( 
							propertyGwtPrefix.concat( gwtTestGwtargsPropertySuffix), 
							"-draftCompile -standardsMode -war ".concat( gwtTestWarDirStr)
								.concat( " -logLevel INFO").concat( " -runStyle HtmlUnit:FF3"));
				}
				else if ( gwtProdTestMode.equals( gwtTestMode)) {
					gwtTestWarDirStr = gwtTestWarDirStr.concat( File.separator).concat( "prod-mode");
					self.getProject()
					.setNewProperty( 
							propertyGwtPrefix.concat( gwtTestGwtargsPropertySuffix), 
							"-prod -standardsMode -war ".concat( gwtTestWarDirStr)
								.concat( " -logLevel INFO"));
				}
			}
		};
		// ----------------------------------------------------------------------------------------
		
		self.log( 
				String.format(
					"END %1$s TASK of %2$s TARGET <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
					new Object[]{ self.getTaskName(), self.getOwningTarget().getName()}
					)
				);
	}
}
